package org.example.mynote.config;

import io.jsonwebtoken.ExpiredJwtException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.example.mynote.Entity.User;
import org.example.mynote.mapper.UserMapper;
import org.example.mynote.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@Component
@Slf4j
public class JwtRequestFilter extends OncePerRequestFilter {

    @Autowired
    private JwtUtil jwtUtil;

    // (可选，但推荐) 注入 UserMapper，以便从数据库验证用户，更安全
    @Autowired
    private UserMapper userMapper;

    public static final String TOKEN_PREFIX = "Bearer ";

    @Override
    protected void doFilterInternal(@NonNull HttpServletRequest request,
                                    @NonNull HttpServletResponse response,
                                    @NonNull FilterChain filterChain)
            throws ServletException, IOException {

        log.info("JWT过滤器执行了，请求路径：{}", request.getRequestURI());

        // 1. 从请求头中获取令牌 (Header: "Authorization")
        String authHeader = request.getHeader("Authorization");

        // 如果 Header 为空，或不以 "Bearer " 开头，直接放行给下一个过滤器（很可能是认证失败的过滤器）
        if (!StringUtils.hasText(authHeader) || !authHeader.startsWith(TOKEN_PREFIX)) {
            filterChain.doFilter(request, response);
            return;
        }

        // 2. 截取真正的 Token
        String token = authHeader.substring(TOKEN_PREFIX.length());

        // 3. 校验并解析令牌
        // 检查当前上下文中是否已经有认证信息，避免重复处理
        if (SecurityContextHolder.getContext().getAuthentication() == null) {
            try {
                String username = jwtUtil.getUsernameFromToken(token);

                // (可选但推荐) 从数据库中加载用户信息，以确认用户存在且账户状态正常（如未被禁用）
                User userFromDb = userMapper.findByUsername(username);

                // 只有当Token有效且数据库中存在该用户时，才进行认证
                if (userFromDb != null && jwtUtil.validateToken(token, username)) {
                    log.info("Token验证通过, 用户名: {}", username);

                    // 2. 创建一个包含基础角色的权限列表
                    // SimpleGrantedAuthority 是 GrantedAuthority 的一个标准实现
                    // "ROLE_USER" 是一个常见的角色名称约定，必须以 "ROLE_" 开头
                    List<SimpleGrantedAuthority> authorities = Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"));

                    // 3. 创建 UserDetails 对象时，传入这个权限列表
                    UserDetails userDetails = new org.springframework.security.core.userdetails.User(
                            username, "[PROTECTED]", authorities
                    );

                    // 4. 创建认证凭证对象时，也把权限列表传进去
                    // 这个构造函数会自动从 userDetails 中获取权限，所以这一步其实可以简化
                    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                            userDetails, null, userDetails.getAuthorities()
                    );

                    authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

                    // ... 后面的 setAuthentication 逻辑不变 ...
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                }

            } catch (ExpiredJwtException e) {
                log.warn("JWT Token has expired: {}", e.getMessage());
                // 这里可以不直接返回401，让后续的Security过滤器链来处理未认证的状态
            } catch (Exception e) {
                log.error("Error during JWT Token validation: {}", e.getMessage());
            }
        }

        // 4. 无论Token验证成功与否，都必须调用 chain.doFilter() 将请求传递下去
        filterChain.doFilter(request, response);
    }
}
